/**
 * @file     Main.cpp
 * @brief    Main file of titere.
 *
 * @author   Franco Riberi
 * @email    fgriberi AT gmail.com
 *
 * Contents: Source file for titere providing Main implementation.
 *
 * System:   titere: Target Ideal TEmperature Rna Expression
 * Language: C++
 *
 * @date January 8, 2014
 *
 * Copyright (C) 2014 Franco Riberi, FuDePAN
 *
 * This file is part of the titere.
 *
 * Titere is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Titere is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with titere. If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <mili/mili.h>
#include <getoptpp/getopt_pp.h>
#include "titere/AnalyzeStructures.h"
#include "titere/Types.h"

/**
 * @brief Responsible to encapsulate the default input values
 */
namespace NSDefaultInValues
{
/** @brief Initial temperature range */
static const NSTitere::Temperature DEFAULT_INITIAL_TEMP = 37;

/** @brief Final temperature range */
static const NSTitere::Temperature DEFAULT_FINAL_TEMP = 42;

/** @brief Tolerance window size */
static const size_t DEFAULT_SIZE_TOLERANCE = 21u;

/** @brief Search type */
static const char DEFAULT_SEARCH[] = "equality";
}

/**
 * @brief Show all titere options usage
 */
void showHelp()
{
    std::cout << "\ntitere: Target Ideal TEmperature Rna Expression\n\n";
    std::cout << "Usage example:\n";
    std::cout << "./install/bin/titere -r install/rnam.fasta -i 37 -f 42 -b UNAFold -l 4\n";
    std::cout << "Required Arguments:\n";
    std::cout << "   -r,   --rnam          : The mRNA file path." << std::endl;
    std::cout << "   -b,   --fold          : The folder backend." << std::endl;
    std::cout << "Optional arguments\n";
    std::cout << "   -h,   --help          : Display this message." << std::endl;
    std::cout << "   -i,   --initTemp      : Initial range of temperature. By default is 37°\n";
    std::cout << "   -f,   --finalTemp     : Final range of temperature. By default is 42°\n";
    std::cout << "   -l,   --lTolerance    : Window size. Must be greater than 19. By default is 21 nucleotides. \n";
    std::cout << "\n";
}

/**
 * @brief Parser input arguments
 *
 * @param args       Object arguments to parse
 * @param titereArgs To fill with the parse result
 */
void parseArguments(GetOpt::GetOpt_pp& args, NSTitere::TitereInputArgs& titereArgs)
{
    //TODO: add prefold options from remo
    args >> GetOpt::OptionPresent('h', "help", titereArgs.help)
         >> GetOpt::OptionPresent('q', "circ", titereArgs.circular)
         >> GetOpt::Option('r', "rnam", titereArgs.fileNameRNAm)
         >> GetOpt::Option('i', "initTemp", titereArgs.initialRangeTemp, NSDefaultInValues::DEFAULT_INITIAL_TEMP)
         >> GetOpt::Option('f', "finalTemp", titereArgs.finalRangeTemp, NSDefaultInValues::DEFAULT_FINAL_TEMP)
         >> GetOpt::Option('b', "fold", titereArgs.folder)
         >> GetOpt::Option('t', "tSearch", titereArgs.typeSearch, NSDefaultInValues::DEFAULT_SEARCH)
         >> GetOpt::Option('l', "lTolerance", titereArgs.lengthTolerance, NSDefaultInValues::DEFAULT_SIZE_TOLERANCE);
    args.end_of_options();
}

/**
 * @brief The Main program
 */
int main(int argc, char* argv[])
{
    size_t ret = EXIT_FAILURE;
    GetOpt::GetOpt_pp args(argc, argv);
    NSTitere::TitereInputArgs titereArgs;

    std::cerr << mili::getGPL3LicenseText("Titere", "1.0", "Franco Riberi", "2014");
    try
    {
        parseArguments(args, titereArgs);
        if (titereArgs.help)
        {
            showHelp();
        }
        else
        {
            NSTitere::AnalyzeStructure analyzeStructure(titereArgs);
            analyzeStructure.foldSequences();
            analyzeStructure.analyzeWindows();
        }
        ret = EXIT_SUCCESS;
    }
    catch (const GetOpt::TooManyOptionsEx&)
    {
        std::cerr << "You specified more options than necessary. Add -h option. \n";
    }
    catch (const GetOpt::GetOptEx&)
    {
        showHelp();
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    catch (...)
    {
        std::cerr << "Unknown error, report this." << std::endl;
    }
    return ret;
}